package com.apes.fn.fico.invoiceApply.service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.apes.fn.crm.customerExpand.FnCustomerExpand;
import com.apes.fn.crm.customerExpand.FnCustomerExpandRepository;
import com.apes.fn.fico.invoiceApply.model.DirectInvoiceApply;
import com.apes.fn.fico.invoiceApply.model.DirectInvoiceApplyItem;
import com.apes.fn.fico.invoiceApply.repository.DirectInvoiceApplyRepository;
import com.apes.fn.scm.retailOrder.model.RetailOrder;
import com.apes.fn.scm.retailOrder.model.RetailOrderItem;
import com.apes.fn.scm.retailOrder.repository.RetailOrderDao;
import com.apes.fn.scm.retailOrder.repository.RetailOrderItemRepository;
import com.apes.fn.scm.retailOrder.repository.RetailOrderRepository;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.logger.ApesLoggerService;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.plugin.soe.store.database.repository.BusinessTypeRepository;
import com.apes.framework.util.Arith;
import com.apes.framework.util.MapUtil;
import com.apes.framework.util.Tools;
import com.apes.scm.account.tax.model.Tax;
import com.apes.scm.masterdata.frame.model.Dept;
import com.apes.scm.masterdata.frame.repository.DeptRepository;
import com.apes.scm.masterdata.party.model.AccessProvider;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.masterdata.party.repository.AccessProviderRepository;
import com.apes.scm.masterdata.party.repository.PartyRoleRepository;
import com.apes.scm.masterdata.product.model.Product;
import com.apes.scm.rbac.model.User;
import com.apes.scm.sal.saleOrder.SaleOrder;
import com.apes.scm.sal.saleOrder.SaleOrderItem;
import com.apes.scm.sal.saleOrder.SaleOrderItemRepository;
import com.apes.scm.sal.saleOrder.SaleOrderRepository;
import com.apes.scm.settle.settle.model.Settle;
import com.apes.scm.settle.settle.model.SettleItem;
import com.apes.scm.settle.settle.model.SettleSimple;
import com.apes.scm.settle.settle.model.SettleSimpleItem;
import com.apes.scm.settle.settle.respository.SettleItemRepository;
import com.apes.scm.settle.settle.respository.SettleRepository;
import com.apestech.framework.util.StringUtil;
import com.apes.scm.settle.settle.respository.SettleSimpleItemRepository;
import com.apes.scm.settle.settle.respository.SettleSimpleRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.persistence.criteria.Predicate;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @BelongsProject: apes-server
 * @BelongsPackage: com.apes.fn.fico.invoiceApply.service
 * @ClassName: DirectInvoiceApplyService
 * @Author: pyb
 * @Description: 直营发票申请服务
 * @CreateTime: 2021-08-12 15:23
 * @Version: 1.0
 */
@Service("directInvoiceApplyService")
public class DirectInvoiceApplyService extends DomainService {
    @Autowired
    private DirectInvoiceApplyRepository directInvoiceApplyRepository;

    @Autowired
    private RetailOrderRepository retailOrderRepository;

    @Autowired
    private RetailOrderItemRepository retailOrderItemRepository;

    @Autowired
    private SaleOrderRepository saleOrderRepository;

    @Autowired
    private SaleOrderItemRepository saleOrderItemRepository;

    @Autowired
    private SettleRepository settleRepository;

    @Autowired
    private SettleItemRepository settleItemRepository;

    @Autowired
    private SettleSimpleRepository settleSimpleRepository;

    @Autowired
    private SettleSimpleItemRepository settleSimpleItemRepository;

    @Autowired
    private RetailOrderDao retailOrderDao;

    /**
     * 保存
     *
     * @param request
     * @return
     */
    public DirectInvoiceApply save(SimpleRequest request) {
        DirectInvoiceApply invoiceApply = request.getO(DirectInvoiceApply.class);
        checkInvoiceType(invoiceApply);
        invoiceApply.setInvoiceApplyItems(invoiceApply.getInvoiceApplyItems().stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(DirectInvoiceApplyItem::getItemId))), ArrayList::new)));
        if (invoiceApply.getInvoiceApplyItems().isEmpty()) {
            throw new RuntimeException("明细不能为空");
        }
        writeOriginOrderInvoiceStatus(invoiceApply,"to_invoice");
        invoiceApply.setState("sent");
        invoiceApply.computeAmt();
        DirectInvoiceApply directInvoiceApply = directInvoiceApplyRepository.saveAndFlush(invoiceApply);
        //增加单据的发票金额
        extracted(directInvoiceApply);
        return directInvoiceApply;

    }

    private void checkInvoiceType(DirectInvoiceApply invoiceApply) {
        boolean isElectronicInvoice  = false;//是否电子发票
        boolean isSpecialInvoice  = false;//是否专用发票
        String invoiceName = invoiceApply.getInvoiceType().getDescription();

        if (invoiceName.contains("专票") || invoiceName.contains("专用发票")) {
            isSpecialInvoice = true;
        }
        if (invoiceName.contains("电子")) {
            isElectronicInvoice = true;
        }
//        if ("电子普通发票".equals(invoiceName) && (invoiceApply.getEmail() == null || "".equals(invoiceApply.getEmail().trim()))) {
//            throw new RuntimeException("电子普通发票邮箱不能为空");
//        }
        //专票必填名称税号
        if (isSpecialInvoice){
            if (invoiceApply.getBuyerName() == null || "".equals(invoiceApply.getBuyerName().trim())){
                throw new RuntimeException("专用发票必须填写名称");
            }
            if (invoiceApply.getBuyerTaxNumber() == null || "".equals(invoiceApply.getBuyerTaxNumber().trim())){
                throw new RuntimeException("专用发票必须填写税号");
            }

        }else {
            if (invoiceApply.getBuyerName() == null || "".equals(invoiceApply.getBuyerName().trim())){
                throw new RuntimeException("普通发票必须填写名称");
            }
        }
        //电子发票必填邮箱
        if (isElectronicInvoice){
            if (invoiceApply.getEmail() == null || "".equals(invoiceApply.getEmail().trim())){
                throw new RuntimeException("电子发票必须填写邮箱");
            }
        }
    }

    private void writeOriginOrderInvoiceStatus(DirectInvoiceApply invoiceApply,String status) {
        Map<String,String> orderMap = new HashMap<String,String>();
        List<DirectInvoiceApplyItem> invoiceApplyItems = invoiceApply.getInvoiceApplyItems();
        for (DirectInvoiceApplyItem invoiceApplyItem : invoiceApplyItems) {
            orderMap.put(invoiceApplyItem.getOrigin(),invoiceApplyItem.getOriginBusinessTypeName());
        }
        Iterator iterator = orderMap.keySet().iterator();
        boolean isFinish = "invoiced".equals(status);
        while (iterator.hasNext()) {
            String key = (String) iterator.next();
            String type = orderMap.get(key);
            switch (type){
                case "零售":
                    retailOrderWriteInvoiceDetail(status, invoiceApply, isFinish, key);
                    break;
                case "结算":
                    settleWriteInvoiceDetail(status, invoiceApply, isFinish, key);
                    break;
                case "客户结算":
                    settleSimpleWriteInvoiceDetail(status, invoiceApply, isFinish, key);
                    break;
                default:
                    saleOrderWriteInvoiceDetail(status, invoiceApply, isFinish, key);
                    break;
            }
        }
    }

    private void retailOrderWriteInvoiceDetail(String status, DirectInvoiceApply invoiceApplyItems, boolean isFinish, String key) {
        //账单状态: ("no", "未开票") (默认值), ("to_invoice", "开票中"), ("invoiced", "已开票")
        RetailOrder retailOrder = retailOrderRepository.findOne(key);
        retailOrder.setInvoiceStatus(status);
        if (isFinish){
            for (RetailOrderItem saleItem : retailOrder.getSaleItems()) {
//                DirectInvoiceApplyItem applyItem = invoiceApplyItems.stream().filter(invoiceApplyItem -> invoiceApplyItem.getItemId().equals(saleItem.getId())).findFirst().orElse(null);
                String invoiceNumber = invoiceApplyItems.getInvoiceNumber();
                if (!Tools.isNull(saleItem.getInvoiceNumber())) {
                    invoiceNumber = saleItem.getInvoiceNumber()+","+invoiceNumber;
                }
//                    if ("no".equals(status))saleItem.setInvoicedAmount(saleItem.getInvoicedAmount() - applyItem.getActualInvoicedAmount());
                saleItem.setInvoiceNumber(invoiceNumber);
            }
        }
        retailOrderRepository.saveAndFlush(retailOrder);
    }

    private void settleWriteInvoiceDetail(String status, DirectInvoiceApply invoiceApplyItems, boolean isFinish, String key) {
        //账单状态: ("no", "未开票") (默认值), ("to_invoice", "开票中"), ("invoiced", "已开票")

        //@State(id = "pending", name = "待开票"),
        //            @State(id = "in", name = "开票中"),
        //            @State(id = "finish", name = "已开票")})
        String settleState = status;
        if ("no".equals(status)){
            settleState = "pending";
        }else if ("to_invoice".equals(status)){
            settleState = "in";
        }else if (isFinish){
            settleState="finish";
        }
        Settle settle = settleRepository.findOne(key);
        if (isFinish){
            for (SettleItem settleItem : settle.getSettleItems()) {
                if (invoiceApplyItems!=null){
                    String invoiceNumber = invoiceApplyItems.getInvoiceNumber();
                    if (!Tools.isNull(settleItem.getInvoiceNumber())) {
                        invoiceNumber = settleItem.getInvoiceNumber()+","+invoiceNumber;
                    }
//                    if ("no".equals(status))settleItem.setInvoicedAmount(settleItem.getInvoicedAmount() - applyItem.getActualInvoicedAmount());
                    settleItem.setInvoiceNumber(invoiceNumber);
                }
            }
        }
        settle.setInvoiceState(settleState);
        settleRepository.saveAndFlush(settle);
    }

    private void saleOrderWriteInvoiceDetail(String status, DirectInvoiceApply invoiceApplyItems, boolean isFinish, String key) {
        //账单状态: ("no", "未开票") (默认值), ("to_invoice", "开票中"), ("invoiced", "已开票")
        SaleOrder saleOrder = saleOrderRepository.findOne(key);
        saleOrder.setInvoiceStatus(status);
        if (isFinish){
            for (SaleOrderItem saleItem : saleOrder.getSaleItems()) {
                if (invoiceApplyItems!=null){
                    String invoiceNumber = invoiceApplyItems.getInvoiceNumber();
                    if (!Tools.isNull(saleItem.getInvoiceNumber())) {
                        invoiceNumber = saleItem.getInvoiceNumber()+","+invoiceNumber;
                    }
//                    if ("no".equals(status))saleItem.setInvoicedAmount(saleItem.getInvoicedAmount() - applyItem.getActualInvoicedAmount());
                    saleItem.setInvoiceNumber(invoiceNumber);
                }
            }
        }
        saleOrderRepository.saveAndFlush(saleOrder);
    }

    /**
     * 客户结算生产发票申请
     * @param status
     * @param invoiceApplyItems
     * @param isFinish
     * @param key
     */
    private void settleSimpleWriteInvoiceDetail(String status,DirectInvoiceApply invoiceApplyItems, boolean isFinish, String key) {
        //账单状态: ("no", "未开票") (默认值), ("to_invoice", "开票中"), ("invoiced", "已开票")

        //@State(id = "pending", name = "待开票"),
        //            @State(id = "in", name = "开票中"),
        //            @State(id = "finish", name = "已开票")})
        String settleState = status;
        if ("no".equals(status)){
            settleState = "pending";
        }else if ("to_invoice".equals(status)){
            settleState = "in";
        }else if (isFinish){
            settleState="finish";
        }
        SettleSimple SettleSimple = settleSimpleRepository.findOne(key);
        if (isFinish){
            for (SettleSimpleItem settleSimpleItem : SettleSimple.getSettleSimpleItems()) {
                if (invoiceApplyItems!=null){
                    String invoiceNumber = invoiceApplyItems.getInvoiceNumber();
                    if (!Tools.isNull(settleSimpleItem.getInvoiceNumber())) {
                        invoiceNumber = settleSimpleItem.getInvoiceNumber()+","+invoiceNumber;
                    }
                    settleSimpleItem.setInvoiceNumber(invoiceNumber);
                }
            }
        }
        SettleSimple.setInvoiceState(settleState);
        settleSimpleRepository.saveAndFlush(SettleSimple);
    }

    /**
     * 修改
     *
     * @param request
     * @return
     */
    public DirectInvoiceApply update(SimpleRequest request) {
        DirectInvoiceApply invoiceApply = request.getO(DirectInvoiceApply.class);
        checkInvoiceType(invoiceApply);
        invoiceApply.setInvoiceApplyItems(invoiceApply.getInvoiceApplyItems().stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(DirectInvoiceApplyItem::getItemId))), ArrayList::new)));

        if (invoiceApply.getInvoiceApplyItems().isEmpty()) {
            throw new RuntimeException("明细不能为空");
        }
        invoiceApply.setState("sent");
        invoiceApply.computeAmt();
        //减少原单据的发票金额
        reduceAmt(directInvoiceApplyRepository.findOne(invoiceApply.getId()));
        DirectInvoiceApply directInvoiceApply = directInvoiceApplyRepository.saveAndFlush(invoiceApply);
        //增加单据的发票金额
        extracted(directInvoiceApply);

        return directInvoiceApply;

    }

    /**
     * 删除
     *
     * @param request
     * @return
     */
    public String delete(SimpleRequest request) {
        DirectInvoiceApply invoiceApply = request.getO(DirectInvoiceApply.class);
        writeOriginOrderInvoiceStatus(invoiceApply,"no");
        //减少原单据的发票金额
        reduceAmt(invoiceApply);
        directInvoiceApplyRepository.delete(invoiceApply);
        return "删除成功";
    }


    /**
     * 申请
     *
     * @param request
     * @return
     */
    public DirectInvoiceApply apply(SimpleRequest request) {
        DirectInvoiceApply invoiceApply = request.getO(DirectInvoiceApply.class);
        checkInvoiceType(invoiceApply);
        invoiceApply.setState("apply");
        invoiceApply.setApplyId(request.getPerson());
        invoiceApply.setApplyDate(new Date());
        try {
            if (invoiceApply.getCompany().getParty().getCorporate().getOperation().getId().equals("001073")) {
                invoiceApply.setNeedOa(false);
            }
        } catch (Exception e) {
            throw new RuntimeException("取运营模式有误,请检查门店的数据是否配置齐全");
        }
        DirectInvoiceApply directInvoiceApply = directInvoiceApplyRepository.saveAndFlush(invoiceApply);
        if (directInvoiceApply.isNeedOa()) {
            invoke("direct.invoiceApply.oa", directInvoiceApply);
        }
        return directInvoiceApply;
    }


    /**
     * 审核
     *
     * @param request
     * @return
     */
    public DirectInvoiceApply approve(SimpleRequest request) {
        DirectInvoiceApply invoiceApply = request.getO(DirectInvoiceApply.class);
        checkInvoiceType(invoiceApply);
        String invoiceNumber = invoiceApply.getInvoiceNumber();
        if (invoiceNumber ==null||"".equals(invoiceNumber.trim()))
            throw new RuntimeException("发票号码未填写");
        invoiceApply.setState("approve");
        invoiceApply.setApproveId(request.getPerson());
        invoiceApply.setApproveDate(new Date());
        writeOriginOrderInvoiceStatus(invoiceApply,"invoiced");
        for (DirectInvoiceApplyItem invoiceApplyItem : invoiceApply.getInvoiceApplyItems()) {
            invoiceApplyItem.setInvoiceNumber(invoiceApply.getInvoiceNumber());
        }
        return directInvoiceApplyRepository.saveAndFlush(invoiceApply);
    }

    /**
     * 编辑
     *
     * @param request
     * @return
     */
    public DirectInvoiceApply edit(SimpleRequest request) {
        DirectInvoiceApply invoiceApply = request.getO(DirectInvoiceApply.class);
        checkInvoiceType(invoiceApply);
        return directInvoiceApplyRepository.saveAndFlush(invoiceApply);
    }

    /**
     * 驳回
     *
     * @param request
     * @return
     */
    public DirectInvoiceApply reject(SimpleRequest request) {
        DirectInvoiceApply invoiceApply = request.getO(DirectInvoiceApply.class);
        invoiceApply.setState("sent");
        invoiceApply.setApproveId(request.getPerson());
        invoiceApply.setApproveDate(new Date());
        return directInvoiceApplyRepository.saveAndFlush(invoiceApply);
    }

    /**
     * 登记
     *
     * @param request
     * @return
     */
    public DirectInvoiceApply register(SimpleRequest request) {
        DirectInvoiceApply directInvoiceApply = request.getO(DirectInvoiceApply.class);
        DirectInvoiceApply invoiceApply = directInvoiceApplyRepository.findOne(directInvoiceApply.getId());
        String number = invoiceApply.getInvoiceNumber();
        if (invoiceApply == null) throw new RuntimeException("状态" + directInvoiceApply.getId() + "】在系统中不存在。");
        if (directInvoiceApply.getVersion() != invoiceApply.getVersion())
            throw new RuntimeException("记录已更新或已删除，请重新提交！");
        invoiceApply.setState("register");
        invoiceApply.setRegisterId(request.getPerson());
        invoiceApply.setRegisterDate(new Date());
        invoiceApply.setInvoiceNumber(directInvoiceApply.getInvoiceNumber());
        invoiceApply.getInvoiceApplyItems().forEach(item -> {
            item.setInvoiceNumber(invoiceApply.getInvoiceNumber());
            if (Objects.equals(item.getOriginBusinessTypeName(), "零售")) {
                RetailOrderItem orderItem = retailOrderItemRepository.findOne(item.getItemId());
                List<String> ids = new ArrayList<>();
                if (!Tools.isNull(orderItem.getInvoiceNumber())) {
                    ids = Stream.of(orderItem.getInvoiceNumber().split(",")).collect(Collectors.toList());
                }
                ids.add(item.getInvoiceApply().getInvoiceNumber());
                orderItem.setInvoiceNumber(ids.stream().filter(k -> !Tools.isNull(k)).collect(Collectors.joining(",")).trim());
                retailOrderItemRepository.save(orderItem);
            } else if (Objects.equals(item.getOriginBusinessTypeName(), "结算")) {
                SettleItem settleItem = settleItemRepository.findOne(item.getItemId());
                List<String> ids = new ArrayList<>();
                if (!Tools.isNull(settleItem.getInvoiceNumber())) {
                    ids = Stream.of(settleItem.getInvoiceNumber().split(",")).collect(Collectors.toList());
                }
                ids.add(item.getInvoiceApply().getInvoiceNumber());
                settleItem.setInvoiceNumber(ids.stream().filter(k -> !Tools.isNull(k)).collect(Collectors.joining(",")).trim());
                settleItemRepository.save(settleItem);
                Settle settle = settleItem.getSettle();
                //设置状态为开票完成
                settle.setInvoiceState("finish");
                settleRepository.save(settle);

            } else {
                SaleOrderItem orderItem = saleOrderItemRepository.findOne(item.getItemId());
                List<String> ids = new ArrayList<>();
                if (!Tools.isNull(orderItem.getInvoiceNumber())) {
                    ids = Stream.of(orderItem.getInvoiceNumber().split(",")).collect(Collectors.toList());
                }
                ids.add(item.getInvoiceApply().getInvoiceNumber());
                orderItem.setInvoiceNumber(ids.stream().filter(k -> !Tools.isNull(k)).collect(Collectors.joining(",")).trim());
                saleOrderItemRepository.save(orderItem);
            }
        });
        String format = String.format("发票号码由 %s 修改为 %s ", number, directInvoiceApply.getInvoiceNumber());
        SpringManager.getBean(ApesLoggerService.class).sendSynEvent("event:ir.logger.create", MapUtil.mapper("businessType", "DirectInvoiceApply",
                "businessKey", directInvoiceApply.getId(), "operate", format,
                "workPostName", request.getSession() != null ? request.getSession().getAttribute("workPostName", String.class) : null,
                "operator_id", ((User) request.getCurrentUser()).getId()));
        return directInvoiceApplyRepository.saveAndFlush(invoiceApply);
    }


    /**
     * 收回
     *
     * @param request
     * @return
     */
    public DirectInvoiceApply revoke(SimpleRequest request) {
        DirectInvoiceApply invoiceApply = request.getO(DirectInvoiceApply.class);
        List<DirectInvoiceApplyItem> invoiceApplyItems = invoiceApply.getInvoiceApplyItems();
        writeOriginOrderInvoiceStatus(invoiceApply,"no");
        DirectInvoiceApply directInvoiceApply = directInvoiceApplyRepository.findOne(invoiceApply.getId());
        if (invoiceApply == null) throw new RuntimeException("状态" + directInvoiceApply.getId() + "】在系统中不存在。");
        if (directInvoiceApply.getVersion() != invoiceApply.getVersion())
            throw new RuntimeException("记录已更新或已删除，请重新提交！");
        directInvoiceApply.setRevokeId(request.getPerson());
        directInvoiceApply.setRevokeDate(new Date());
        directInvoiceApply.setState("stop");
        directInvoiceApply.getInvoiceApplyItems().forEach(item -> {
            if (Objects.equals(item.getOriginBusinessTypeName(), "零售")) {
                RetailOrderItem orderItem = retailOrderItemRepository.findOne(item.getItemId());
                if (!Tools.isNull(orderItem.getInvoiceNumber())) {
                    List<String> ids = Stream.of(orderItem.getInvoiceNumber().split(",")).collect(Collectors.toList());
                    ids.removeIf(i -> Objects.equals(invoiceApply.getInvoiceNumber(), i));
                    orderItem.setInvoiceNumber(ids.stream().filter(k -> !Tools.isNull(k)).collect(Collectors.joining(",")).trim());
                    orderItem.setInvoicedAmount(orderItem.getInvoicedAmount() - item.getActualInvoicedAmount());
                    retailOrderItemRepository.save(orderItem);
                    RetailOrder order = orderItem.getOrder();
                    order.setInvoicedAmount(order.getInvoicedAmount() - item.getActualInvoicedAmount());
                    retailOrderRepository.save(order);
                }
            } else if (Objects.equals(item.getOriginBusinessTypeName(), "结算")) {
                SettleItem settleItem = settleItemRepository.findOne(item.getItemId());
                if (!Tools.isNull(settleItem.getInvoiceNumber())) {
                    List<String> ids = Stream.of(settleItem.getInvoiceNumber().split(",")).collect(Collectors.toList());
                    ids.removeIf(i -> Objects.equals(invoiceApply.getInvoiceNumber(), i));
                    settleItem.setInvoiceNumber(ids.stream().filter(k -> !Tools.isNull(k)).collect(Collectors.joining(",")).trim());
                    settleItem.setInvoicedAmount(settleItem.getInvoicedAmount() - item.getActualInvoicedAmount());
                    settleItemRepository.save(settleItem);
                    Settle settle = settleItem.getSettle();
                    settle.setInvoicedAmount(settle.getInvoicedAmount() - item.getActualInvoicedAmount());
                    settle.setInvoiceState("pending");
                    settleRepository.save(settle);
                }
                settleItemRepository.save(settleItem);
            } else if (Objects.equals(item.getOriginBusinessTypeName(), "客户结算")) {
                SettleSimpleItem settleSimpleItem = settleSimpleItemRepository.findOne(item.getItemId());
                if (!Tools.isNull(settleSimpleItem.getInvoiceNumber())) {
                    List<String> ids = Stream.of(settleSimpleItem.getInvoiceNumber().split(",")).collect(Collectors.toList());
                    ids.removeIf(i -> Objects.equals(invoiceApply.getInvoiceNumber(), i));
                    settleSimpleItem.setInvoiceNumber(ids.stream().filter(k -> !Tools.isNull(k)).collect(Collectors.joining(",")).trim());
                    settleSimpleItem.setInvoicedAmount(settleSimpleItem.getInvoicedAmount() - item.getActualInvoicedAmount());
                    settleSimpleItemRepository.save(settleSimpleItem);
                    SettleSimple settleSimple = settleSimpleItem.getSettleSimple();
                    settleSimple.setInvoicedAmount(settleSimple.getInvoicedAmount() - item.getActualInvoicedAmount());
                    settleSimple.setInvoiceState("pending");
                    settleSimpleRepository.save(settleSimple);
                }
                settleSimpleItemRepository.save(settleSimpleItem);
            } else {
                SaleOrderItem orderItem = saleOrderItemRepository.findOne(item.getItemId());
                if (!Tools.isNull(orderItem.getInvoiceNumber())) {
                    List<String> ids = Stream.of(orderItem.getInvoiceNumber().split(",")).collect(Collectors.toList());
                    ids.removeIf(i -> Objects.equals(invoiceApply.getInvoiceNumber(), i));
                    orderItem.setInvoiceNumber(ids.stream().filter(k -> !Tools.isNull(k)).collect(Collectors.joining(",")).trim());
                    orderItem.setInvoicedAmount(orderItem.getInvoicedAmount() - item.getActualInvoicedAmount());
                    saleOrderItemRepository.save(orderItem);
                    SaleOrder saleOrder = orderItem.getSaleOrder();
                    saleOrder.setInvoicedAmount(saleOrder.getInvoicedAmount() - item.getActualInvoicedAmount());
                    saleOrderRepository.save(saleOrder);
                }
            }
            item.setMark(true);
            item.setInvoiceNumber(null);
        });
        return directInvoiceApplyRepository.saveAndFlush(directInvoiceApply);
    }

    /**
     * 减少原单据的发票金额
     *
     * @param invoiceApply
     */
    public void reduceAmt(DirectInvoiceApply invoiceApply) {
        directInvoiceApplyRepository.findOne(invoiceApply.getId()).getInvoiceApplyItems().forEach(item -> {
            if (Objects.equals(item.getOriginBusinessTypeName(), "零售")) {
                RetailOrderItem orderItem = retailOrderItemRepository.findOne(item.getItemId());
                orderItem.setInvoicedAmount(orderItem.getInvoicedAmount() - item.getActualInvoicedAmount());
                retailOrderItemRepository.save(orderItem);
                RetailOrder order = orderItem.getOrder();
                order.setInvoicedAmount(order.getInvoicedAmount() - item.getActualInvoicedAmount());
                retailOrderRepository.save(order);
            } else if (Objects.equals(item.getOriginBusinessTypeName(), "结算")) {
                SettleItem settleItem = settleItemRepository.findOne(item.getItemId());
                settleItem.setInvoicedAmount(settleItem.getInvoicedAmount() - item.getActualInvoicedAmount());
                settleItemRepository.save(settleItem);
                Settle settle = settleItem.getSettle();
                settle.setInvoicedAmount(settle.getInvoicedAmount() - item.getActualInvoicedAmount());
                settle.setInvoiceState("pending");
                settleRepository.save(settle);
            } else {
                SaleOrderItem orderItem = saleOrderItemRepository.findOne(item.getItemId());
                orderItem.setInvoicedAmount(orderItem.getInvoicedAmount() - item.getActualInvoicedAmount());
                saleOrderItemRepository.save(orderItem);
                SaleOrder saleOrder = orderItem.getSaleOrder();
                saleOrder.setInvoicedAmount(saleOrder.getInvoicedAmount() - item.getActualInvoicedAmount());
                saleOrderRepository.save(saleOrder);
            }
        });
    }


    /**
     * 增加单据的发票金额
     *
     * @param directInvoiceApply
     */
    private void extracted(DirectInvoiceApply directInvoiceApply) {
        //增加单据的发票金额
        directInvoiceApply.getInvoiceApplyItems().forEach(item -> {
            if (Objects.equals(item.getOriginBusinessTypeName(), "零售")) {
                RetailOrderItem orderItem = retailOrderItemRepository.findOne(item.getItemId());
                orderItem.setInvoicedAmount(orderItem.getInvoicedAmount() + item.getActualInvoicedAmount());
                retailOrderItemRepository.save(orderItem);
                RetailOrder order = orderItem.getOrder();
                order.setInvoicedAmount(order.getInvoicedAmount() + item.getActualInvoicedAmount());
                if (order.getInvoicedAmount() - order.getActualAmount() > 0.0001) { //允许存在误差问题
                    throw new RuntimeException(String.format("零售单[%s]开票金额大于实收金额！无法再次开票！", order.getId()));
                }
                retailOrderRepository.save(order);
            } else if (Objects.equals(item.getOriginBusinessTypeName(), "结算")) {
                SettleItem settleItem = settleItemRepository.findOne(item.getItemId());
                settleItem.setInvoicedAmount(settleItem.getInvoicedAmount() + item.getActualInvoicedAmount());
                settleItemRepository.save(settleItem);
                Settle settle = settleItem.getSettle();
                settle.setInvoicedAmount(settle.getInvoicedAmount() + item.getActualInvoicedAmount());
                //设置状态为开票中
                settle.setInvoiceState("in");
                settleRepository.save(settle);
            } else if (Objects.equals(item.getOriginBusinessTypeName(), "客户结算")) {
                SettleSimpleItem settleSimpleItem = settleSimpleItemRepository.findOne(item.getItemId());
                settleSimpleItem.setInvoicedAmount(settleSimpleItem.getInvoicedAmount() + item.getActualInvoicedAmount());
                settleSimpleItemRepository.save(settleSimpleItem);
                SettleSimple settleSimple = settleSimpleItem.getSettleSimple();
                settleSimple.setInvoicedAmount(settleSimple.getInvoicedAmount() + item.getActualInvoicedAmount());
                //设置状态为开票中
                settleSimple.setInvoiceState("in");
                settleSimpleRepository.save(settleSimple);
            } else {
                SaleOrderItem orderItem = saleOrderItemRepository.findOne(item.getItemId());
                orderItem.setInvoicedAmount(orderItem.getInvoicedAmount() + item.getActualInvoicedAmount());
                saleOrderItemRepository.save(orderItem);

                SaleOrder saleOrder = orderItem.getSaleOrder();
                saleOrder.setInvoicedAmount(saleOrder.getInvoicedAmount() + item.getActualInvoicedAmount());
                if (saleOrder.getInvoicedAmount() > saleOrder.getActualAmount()) {
                    throw new RuntimeException(String.format("分销单[%s]开票金额大于实收金额！无法再次开票！", saleOrder.getId()));
                }
                saleOrderRepository.save(saleOrder);
            }
        });
    }

    /**
     * 获取单据信息
     *
     * @param request
     * @return
     */

    public Map findOrderInfo(SimpleRequest request) {
        JSONObject param = request.getJO();

        JSONObject model = new JSONObject();
        JSONArray condition = param.getJSONArray("condition");
        condition.forEach(x -> {
            JSONObject jsonObject = (JSONObject) x;
            model.put((String) jsonObject.get("field") + jsonObject.get("operator"), jsonObject.get("value"));
        });

        // 查询条件
        JSONObject conditionModel = param.getJSONObject("conditionModel");
        String deptId = Objects.isNull(conditionModel.getJSONObject("dept")) ? "" : conditionModel.getJSONObject("dept").getString("id");
        String companyId = conditionModel.getJSONObject("company").getString("id");

        PartyRole company = companyId != null ? SpringManager.getBean(PartyRoleRepository.class).findOne(companyId) : null;
        Dept dept = deptId != null ? SpringManager.getBean(DeptRepository.class).findOne(deptId) : null;
        String saleCategoryId = conditionModel.getString("saleCategory");

        // 具体查询
        if ("retail".equals(saleCategoryId)) {
            // 零售单查询
            return retailQuery(request, model, condition, deptId, companyId);
        } else {
            // 分销单查询
            return saleQuery(request, model, company, dept);
        }
    }

    private Map retailQuery(SimpleRequest request, JSONObject model, JSONArray condition, String deptId, String companyId) {
        JSONObject json = request.getJO();

        //页面中已有的数据
        JSONObject param = parseCondition(json.getJSONArray("condition"));

        JSONArray all = retailOrderDao.findDept(param,deptId);

        JSONObject result = new JSONObject();
        result.put("content", all);
        return result;
    }

    /**
     * 解析前端参数
     *
     * @param array filter 参数，解析日期格式
     * @return
     */
    public JSONObject parseCondition(JSONArray array) {
        JSONObject model = new JSONObject();
        array.forEach(v -> {
            JSONObject filter = (JSONObject) v;
            if ("GTE".equals(filter.getString("operator")) && "dateApprove".equals(filter.getString("field"))) {
                model.put(filter.getString("field") + "_DATE", filter.getString("value"));//因时间类型的查询条件有两个值，不好区分,所以在字段名后加_DATE
            } else {
                model.put(filter.getString("field"), filter.get("value"));
            }
        });
        return model;
    }


    private Map saleQuery(SimpleRequest request, JSONObject model, PartyRole company, Dept dept) {
        // 拼接查询条件
        Specification<SaleOrder> specification = (root, query, criteriaBuilder) -> {
            List<Predicate> predicates = new LinkedList<>();
            if (dept != null) predicates.add(criteriaBuilder.equal(root.get("dept"), dept));
            if (dept == null) predicates.add(criteriaBuilder.equal(root.get("company"), company));
            predicates.add(criteriaBuilder.gt(root.get("actualAmount"), root.get("invoicedAmount")));
            predicates.add(criteriaBuilder.gt(root.get("actualAmount"), 0));
            if (model.containsKey("dateApproveGTE")) {
                predicates.add(criteriaBuilder.greaterThan(root.get("dateApprove"), model.getDate("dateApproveGTE")));
                predicates.add(criteriaBuilder.lessThan(root.get("dateApprove"), model.getDate("dateApproveLTE")));
            }
            Predicate resultAnd[] = predicates.toArray(new Predicate[predicates.size()]);
            Predicate predicate = criteriaBuilder.and(criteriaBuilder.and(resultAnd));

            List<Predicate> predicates3 = new LinkedList<>();
            if (model.containsKey("orderInfoEQ")) {
                String orderInfo = (String) model.get("orderInfoEQ");
                predicates3.add(criteriaBuilder.equal(root.get("id"), orderInfo));
                predicates3.add(criteriaBuilder.equal(root.get("source"), orderInfo));
                try {
                    predicates3.add(criteriaBuilder.equal((root.get("actualAmount")), model.getDoubleValue("orderInfoEQ")));
                } catch (Exception e) {
                }
                predicate = criteriaBuilder.and(criteriaBuilder.and(resultAnd), criteriaBuilder.or(predicates3.toArray(new Predicate[predicates3.size()])));
            }

            if (model.containsKey("carInfoEQ")) {
                List<Predicate> predicates2 = new LinkedList<>();
                String carInfo = (String) model.get("carInfoEQ");
                List<FnCustomerExpand> fnCustomerExpands = SpringManager.getBean(FnCustomerExpandRepository.class).findAllByMobileOrCarLicenseOrRealname(carInfo, carInfo, carInfo);
                if (!fnCustomerExpands.isEmpty()) {
                    predicates2.add(criteriaBuilder.in(root.get("FnCustomerExpandId")).value(fnCustomerExpands.stream().map(FnCustomerExpand::getId).collect(Collectors.toList())));
                }
                if (!model.containsKey("orderInfoEQ") || fnCustomerExpands.isEmpty()) {
                    predicate = criteriaBuilder.and(criteriaBuilder.and(resultAnd), criteriaBuilder.or(predicates2.toArray(new Predicate[predicates2.size()])));
                } else {
                    predicate = criteriaBuilder.and(criteriaBuilder.and(resultAnd), criteriaBuilder.or(predicates2.toArray(new Predicate[predicates2.size()])), criteriaBuilder.or(predicates3.toArray(new Predicate[predicates3.size()])));
                }

            }
            return predicate;
        };

        // 查询分销单
        Page page = saleOrderRepository.findAll(specification, PageRequest.of(request.get("page"), request.get("size"), new Sort(Sort.Direction.DESC, "id")));
        Map mapped = MapUtil.mapped(page);
        ((List<Map>) (mapped != null ? mapped.get("content") : null)).forEach(order -> {
            FnCustomerExpand fnCustomerExpand = order.get("FnCustomerExpandId") != null ? SpringManager.getBean(FnCustomerExpandRepository.class).findOne((String) order.get("FnCustomerExpandId")) : new FnCustomerExpand();
            order.put("realname", order.get("FnCustomerExpandId") != null ? fnCustomerExpand.getRealname() : "");
            order.put("carLicense", order.get("FnCustomerExpandId") != null ? fnCustomerExpand.getCarLicense() : "");
            order.put("orderName", "分销");
            order.put("originBusinessType", order.get("originBusinessType") != null ? SpringManager.getBean(BusinessTypeRepository.class).findOne((String) order.get("originBusinessType")).getName() : "");
            order.put("approveUID", order.get("creator") != null ? SpringManager.getBean(PartyRoleRepository.class).findOne((String) order.get("creator")) : "");
            order.put("fnCustomerExpand", order.get("FnCustomerExpandId") != null ? fnCustomerExpand : "");
        });
        return mapped;
    }


    /**
     * 获取单据明细
     *
     * @param request
     * @return
     */
    public List<Map> findOrderItem(SimpleRequest request) {
        String saleCategory = request.get("saleCategory");
        String deptId = request.get("deptId");
        Map requestMap = request.getMap();
        if (requestMap.containsKey("orderId")) {
            String orderId = (String) requestMap.get("orderId");
            if (Objects.equals("retail", saleCategory)) {
                return retailOrderRepository.findOne(orderId).getSaleItems().stream().filter(retailOrderItem -> (retailOrderItem.getProductUomQty() - retailOrderItem.getQtyReturned() - retailOrderItem.getQtyReturning()) > 0).map(item -> getMap(extractedOrderItem(item), item.getInvoicedAmount(), item.getTax(), item.getProduct())).collect(Collectors.toList());
            } else {
                return saleOrderRepository.findOne(orderId).getSaleItems().stream().filter(saleOrderItem -> saleOrderItem.getQtyReturned() == 0 && saleOrderItem.getQtyReturning() == 0).map(item -> getMap(extractedSaleOrderItem(item), item.getInvoicedAmount(), item.getTax(), item.getProduct())).collect(Collectors.toList());
            }
        } else {
            String carId = (String) requestMap.get("carId");

            List<Map> result = new ArrayList<>();
            if ("A".equals(deptId)) {
                String company = request.get("company");
                if (Objects.equals("retail", saleCategory)) {
                    retailOrderRepository.findAll(JpaDsl.toCriteriaByEq("customerExpand.id", carId, "company.id", company)).stream().forEach(retailOrder -> retailOrder.getSaleItems().stream().filter(retailOrderItem -> (retailOrderItem.getProductUomQty() - retailOrderItem.getQtyReturned() - retailOrderItem.getQtyReturning()) > 0).forEach(item -> result.add(getMap(extractedOrderItem(item), item.getInvoicedAmount(), item.getTax(), item.getProduct()))));
                } else {
                    saleOrderRepository.findAll(JpaDsl.toCriteriaByEq("FnCustomerExpandId", carId, "company.id", company)).stream().forEach(saleOrder -> saleOrder.getSaleItems().stream().filter(saleOrderItem -> saleOrderItem.getQtyReturned() == 0 && saleOrderItem.getQtyReturning() == 0).forEach(item -> result.add(getMap(extractedSaleOrderItem(item), item.getInvoicedAmount(), item.getTax(), item.getProduct()))));
                }
            } else {
                if (Objects.equals("retail", saleCategory)) {
                    retailOrderRepository.findAll(JpaDsl.toCriteriaByEq("customerExpand.id", carId, "dept.id", deptId)).stream().forEach(retailOrder -> retailOrder.getSaleItems().stream().filter(retailOrderItem -> (retailOrderItem.getProductUomQty() - retailOrderItem.getQtyReturned() - retailOrderItem.getQtyReturning()) > 0).forEach(item -> result.add(getMap(extractedOrderItem(item), item.getInvoicedAmount(), item.getTax(), item.getProduct()))));
                } else {
                    saleOrderRepository.findAll(JpaDsl.toCriteriaByEq("FnCustomerExpandId", carId, "dept.id", deptId)).stream().forEach(saleOrder -> saleOrder.getSaleItems().stream().filter(saleOrderItem -> saleOrderItem.getQtyReturned() == 0 && saleOrderItem.getQtyReturning() == 0).forEach(item -> result.add(getMap(extractedSaleOrderItem(item), item.getInvoicedAmount(), item.getTax(), item.getProduct()))));
                }
            }
            return result;
        }

    }

    /**
     * 提取拼接分销订单明细的重复代码
     *
     * @param item
     * @return
     */
    public Map extractedSaleOrderItem(SaleOrderItem item) {
        Map orderItem = new HashMap();
        orderItem.put("uom", item.getUom());
        orderItem.put("itemId", item.getId());
        orderItem.put("product", item.getProduct());
        orderItem.put("originBusinessTypeName", "分销");
        orderItem.put("priceTotal", item.getPriceTotal() - item.getDiscount());
        orderItem.put("origin", item.getSaleOrder().getId());
        orderItem.put("productQty", item.getProductUomQty());
        orderItem.put("source", item.getSaleOrder().getOrigin());
        orderItem.put("actualInvoicedAmount", Arith.sub(item.getPriceTotal(), item.getInvoicedAmount()));
        FnCustomerExpand customerExpand = null;
        if (item.getSaleOrder().getFnCustomerExpandId() != null)
            customerExpand = SpringManager.getBean(FnCustomerExpandRepository.class).findOne(item.getSaleOrder().getFnCustomerExpandId());

        orderItem.put("customerExpand", customerExpand);
        orderItem.put("carLicense", customerExpand != null ? customerExpand.getCarLicense() : null);

        orderItem.put("sourceBusinessTypeName", item.getSaleOrder().getOriginBusinessType() != null ? SpringManager.getBean(BusinessTypeRepository.class).findOne(item.getSaleOrder().getOriginBusinessType()).getName() : null);
        return orderItem;
    }


    /**
     * 提取拼接零售订单明细的重复代码
     *
     * @param item
     * @return
     */
    public Map extractedOrderItem(RetailOrderItem item) {
        Map orderItem = new HashMap();
        orderItem.put("uom", item.getUom());
        orderItem.put("itemId", item.getId());
        orderItem.put("product", item.getProduct());
        orderItem.put("originBusinessTypeName", "零售");
        orderItem.put("origin", item.getOrder().getId());
        orderItem.put("source", item.getOrder().getOrigin());
        orderItem.put("productQty", item.getProductUomQty());
        orderItem.put("customerExpand", item.getOrder().getCustomerExpand());
        double total = Arith.sub(item.getPriceTotal(), item.getDiscountAmount());
        orderItem.put("priceTotal", total);
        orderItem.put("actualInvoicedAmount", Arith.sub(total, item.getInvoicedAmount()));
        orderItem.put("carLicense", item.getOrder().getCustomerExpand().getCarLicense());
        orderItem.put("sourceBusinessTypeName", "server".equals(item.getOrder().getOrderType()) ? "服务" : ("yearcard".equals(item.getOrder().getOrderType()) ? "年卡" : item.getOrder().getOrderType()));
        return orderItem;
    }

    /**
     * 查询车主信息
     *
     * @param request
     * @return
     */
    public Page<FnCustomerExpand> findCarInfo(SimpleRequest request) {
        JSONObject model = new JSONObject();
        Map requestMap = request.getMap();
        if (requestMap.containsKey("key")) {
            model.put("carInfo", requestMap.get("key"));
        } else {
            List<Map> condition = request.get("condition");
            condition.forEach(x -> {
                JSONObject jsonObject = (JSONObject) x;
                model.put(jsonObject.getString("field"), jsonObject.get("value"));
            });
        }
        Page<FnCustomerExpand> page = null;
        String company = model.getString("company");
        AccessProvider accessProvider = SpringManager.getBean(AccessProviderRepository.class).findByCompany(company);
        if (Objects.isNull(accessProvider)) {
            throw new RuntimeException("所选公司无接入商");
        }
        if (model.containsKey("carInfo")) {
            String carInfo = model.getString("carInfo");
            page = SpringManager.getBean(FnCustomerExpandRepository.class).findAllByMobileOrCarLicenseOrRealnameAndVendorCode(carInfo, carInfo, carInfo, accessProvider.getId(), PageRequest.of(request.get("page"), request.get("size"), new Sort(Sort.Direction.DESC, "id")));
        } else {
            page = SpringManager.getBean(FnCustomerExpandRepository.class).findAll(JpaDsl.toCriteriaByEq("vendorCode", accessProvider.getId()), PageRequest.of(request.get("page"), request.get("size"), new Sort(Sort.Direction.DESC, "id")));
        }
        return page;
    }

    /**
     * 提取的重复代码
     *
     * @param orderItem
     * @param invoicedAmount
     * @param tax
     * @param product
     * @return
     */
    public Map getMap(Map orderItem, double invoicedAmount, Tax tax, Product product) {
        orderItem.put("mark", 0);
        orderItem.put("tax", tax);
        orderItem.put("model", product.getModel());
        orderItem.put("invoicedAmount", invoicedAmount);
        orderItem.put("serveType", product.queryServeType());
        orderItem.put("productGroup", product.getProductGroup());
        orderItem.put("specifications", product.getSpecifications());
        return orderItem;
    }


    /**
     * 查询购方名称
     */
    public Page<DirectInvoiceApply> findBuyerName(SimpleRequest request) {
        String key = request.get("key");
        return directInvoiceApplyRepository.findBuyerName(key, PageRequest.of(request.get("page"), request.get("size")));
    }
}
